﻿using System;
using System.Transactions;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using O1.Kernel;
using O1.Kernel.Storage.Transactions;

namespace Tests.O1.Kernel.Storage.Transactions
{
    [TestClass]
    public class TxVisibilityTests
    {
        #region ReadCommitted

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation1AIsAsExpected()
        {
            ////1A - Less than Begin Tx : Begin TX Uncommitted, End Tx infinity ----
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Pending);
            var tx = new Tx(addedTx, ulong.MaxValue);

            var visibilities = tx.ResolveVisibilities(97);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation1BIsAsExpected()
        {
            ////1B - Less than Begin Tx : Begin Tx Committed, End Tx infinity ----
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);
            var tx = new Tx(addedTx, ulong.MaxValue);

            var visibilities = tx.ResolveVisibilities(97);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation1CIsAsExpected()
        {
            ////1C - Less than Begin Tx : Begin TX Committed, End Tx Uncommitted ----
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);
            ulong deletedTx = ((ulong)120).EmbedStatus(TxStatus.Pending);

            var tx = new Tx(addedTx, deletedTx);

            var visibilities = tx.ResolveVisibilities(97);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation1DIsAsExpected()
        {
            ////1D - Less than Begin Tx : Begin Tx Committed, End Tx Committed ----
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);
            ulong deletedTx = ((ulong)120).EmbedStatus(TxStatus.Committed);

            var tx = new Tx(addedTx, deletedTx);

            var visibilities = tx.ResolveVisibilities(97);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation2AIsAsExpected()
        {
            ////2A - Equal to Begin Tx : Begin TX Uncommitted, End Tx infinity +-+-
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Pending);

            var tx = new Tx(addedTx, ulong.MaxValue);

            var visibilities = tx.ResolveVisibilities((ulong)99);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation3AIsAsExpected()
        {
            ////3A - Greater than Begin TX and less than End Tx : Begin TX Uncommitted, End Tx infinity --+-
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Pending);

            var tx = new Tx(addedTx, ulong.MaxValue);

            var visibilities = tx.ResolveVisibilities(110);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation3BIsAsExpected()
        {
            ////3B - Greater than Begin TX and less than End Tx : Begin Tx Committed, End Tx infinity +-+-
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);

            var tx = new Tx(addedTx, ulong.MaxValue);

            var visibilities = tx.ResolveVisibilities(110);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation3CIsAsExpected()
        {
            ////3C - Greater than Begin TX and less than End Tx : Begin TX Committed, End Tx Uncommitted --++
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);
            ulong deletedTx = ((ulong)120).EmbedStatus(TxStatus.Pending);

            var tx = new Tx(addedTx, deletedTx);

            var visibilities = tx.ResolveVisibilities(110);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeTrue();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation3DIsAsExpected()
        {
            ////3D - Greater than Begin TX and less than End Tx : Begin Tx Committed, End Tx Committed +-++
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);
            ulong deletedTx = ((ulong)120).EmbedStatus(TxStatus.Committed);

            var tx = new Tx(addedTx, deletedTx);

            var visibilities = tx.ResolveVisibilities(110);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeTrue();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation4CIsAsExpected()
        {
            ////4C - Equal to End Tx : Begin TX Committed, End Tx Uncommitted +-+-
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);
            ulong deletedTx = ((ulong)120).EmbedStatus(TxStatus.Pending);

            var tx = new Tx(addedTx, deletedTx);

            var visibilities = tx.ResolveVisibilities(120);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation5CIsAsExpected()
        {
            ///5C - Greater than End Tx : Begin TX Committed, End Tx Uncommitted --++
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);
            ulong deletedTx = ((ulong)120).EmbedStatus(TxStatus.Pending);

            var tx = new Tx(addedTx, deletedTx);

            var visibilities = tx.ResolveVisibilities(121);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeTrue();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeTrue();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void TxVisbilityForReadCommittedPermutation5DIsAsExpected()
        {
            ////5D - Greater than End Tx : Begin Tx Committed, End Tx Committed ----
            ulong addedTx = ((ulong)99).EmbedStatus(TxStatus.Committed);
            ulong deletedTx = ((ulong)120).EmbedStatus(TxStatus.Committed);

            var tx = new Tx(addedTx, deletedTx);

            var visibilities = tx.ResolveVisibilities(121);
            visibilities.HasFlag(TxValidations.ReadVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ReadInvalid).Should().BeFalse();
            visibilities.HasFlag(TxValidations.ScopeVisible).Should().BeFalse();
            visibilities.HasFlag(TxValidations.WriteConflict).Should().BeFalse();
        }

        #endregion
    }
}
